package com.yeskery.nut.bean;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * Bean注解方法后置处理接口，该方法用于处理在bean方法上添加注解增强额外业务的方法
 * @author sprout
 * @version 1.0
 * 2022-11-17 13:48
 */
public abstract class BaseAnnotationMethodBeanPostProcessor implements BeanPostProcessor {
    @Override
    public void process(Object bean, Class<?> beanClass, ApplicationContext applicationContext, FactoryBeanRegister factoryBeanRegister) {
        Class<? extends Annotation> methodAnnotation = getMethodTargetAnnotation();
        for (Method method : beanClass.getMethods()) {
            if (isValidMethod(method, methodAnnotation)) {
                doProcess(bean, beanClass, method, applicationContext, factoryBeanRegister);
            }
        }
    }

    /**
     * 获取方法上的注解
     * @return 方法上的注解
     */
    protected abstract Class<? extends Annotation> getMethodTargetAnnotation();

    /**
     * 处理方法
     * @param bean bean对象
     * @param beanClass bean类
     * @param method 方法对象
     * @param applicationContext 应用上下文
     * @param factoryBeanRegister 工厂bean注册
     */
    protected abstract void doProcess(Object bean, Class<?> beanClass, Method method, ApplicationContext applicationContext, FactoryBeanRegister factoryBeanRegister);

    /**
     * 是否是有效的方法
     * @param method 方法对象
     * @param mcpAnnotationClass Mcp注解类
     * @return 是否是有效的方法
     */
    protected boolean isValidMethod(Method method, Class<? extends Annotation> mcpAnnotationClass) {
        int modifiers = method.getModifiers();
        return !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers) && Modifier.isPublic(modifiers)
                && method.isAnnotationPresent(mcpAnnotationClass);
    }

    /**
     * 获取注解
     * @param method 方法对象
     * @param annotationClass 注解类
     * @param <T> 注解类型
     * @return 注解对象
     */
    protected <T extends Annotation> T getMethodAnnotation(Method method, Class<T> annotationClass) {
        return method.getAnnotation(annotationClass);
    }
}
